import pinyin from 'js-pinyin'

export const StringUtil = {
  /**
   * 去两端空格
   * @returns {trim}
   */
  trim (str) {
    return StringUtil.isString(str) ? str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '') : str
  },
  /**
   * 转换字符串，undefined,null等转化为""
   * @param str
   * @returns {*}
   */
  parseString (str) {
    return StringUtil.isEmpty(str) ? '' : str
  },
  /**
   *
   * @returns {string}
   */
  getUuid () {
    const timestamp = +new Date() + ''
    const randomNum = parseInt((1 + Math.random()) * 65536) + ''
    return (+(randomNum + timestamp)).toString(32)
  },
  // 首字母大小
  titleCase (str) {
    return str.replace(/( |^)[a-z]/g, L => L.toUpperCase())
  },
  // 下划转驼峰
  camelCase (str) {
    return str.replace(/-[a-z]/g, str1 => str1.substr(-1).toUpperCase())
  },
  /**
   * @param {string} input value
   * @returns {number} output value
   */
  byteLength (str) {
    // returns the byte length of an utf8 string
    let s = str.length
    for (var i = str.length - 1; i >= 0; i--) {
      const code = str.charCodeAt(i)
      if (code > 0x7f && code <= 0x7ff) s++
      else if (code > 0x7ff && code <= 0xffff) s += 2
      if (code >= 0xDC00 && code <= 0xDFFF) i--
    }
    return s
  },
  /**
   * 获取系统操作异常消息
   * @param ex
   * @returns {string}
   */
  getExceptionMessage (ex) {
    const errMsg = '系统繁忙，请稍后重试'
    return !ex.includes('Lock wait timeout exceeded') ? ex : errMsg
  },
  /**
   * 四舍五入
   * @returns {trim}
   */
  toFixed (val, decimal) {
    return this.isNumber(val) ? Number(Number(val).toFixed(decimal || 8)) : null
  },
  /**
   * 合计数组元素值
   * @param arr 待合计的数组
   * @param key 数组中的对象元素key
   * @param decimal 合计后的数值精度
   * @returns {*}
   */
  sum (arr = [], decimal, key) {
    if (!this.isEmpty(arr)) {
      let total = 0
      for (let i = 0; i < arr.length; i++) {
        const item = arr[i]
        let val
        if (key) {
          if (item[key] !== undefined) {
            val = Number(item[key])
          }
        } else {
          val = Number(item)
        }
        if (!isNaN(val)) {
          total = total.add(val)
        }
      }
      if (decimal === undefined) decimal = 8
      if (!isNaN(total) && !isNaN(decimal)) {
        return Number(total.toFixed(decimal))
      }
      return total
    }

    return null
  },
  /**
   * 两数相加
   * @param val1 被减数
   * @param val2 减数
   */
  add (val1, val2, decimal) {
    val1 = Number(val1)
    val2 = Number(val2)

    if (isNaN(val1) || isNaN(val1)) {
      return null
    }
    const val = val1.add(val2)
    if (decimal === undefined) decimal = 8
    if (!isNaN(val) && !isNaN(decimal)) {
      return Number(val.toFixed(decimal))
    }
    return val
  },
  /**
   * 两数相减
   * @param val1 被减数
   * @param val2 减数
   */
  sub (val1, val2, decimal) {
    val1 = Number(val1)
    val2 = Number(val2)
    if (isNaN(val1) || isNaN(val1)) {
      return null
    }
    const val = val1.sub(val2)
    if (decimal === undefined) decimal = 8
    if (!isNaN(val) && !isNaN(decimal)) {
      return Number(val.toFixed(decimal))
    }
    return val
  },
  /**
   * 两数相乘
   * @param val1 被乘数
   * @param val2 乘数
   */
  multiply (val1, val2, decimal) {
    val1 = Number(val1)
    val2 = Number(val2)
    if (isNaN(val1) || isNaN(val1)) {
      return null
    }
    const val = val1.mul(val2)
    if (decimal === undefined) decimal = 8
    if (!isNaN(val) && !isNaN(decimal)) {
      return Number(val.toFixed(decimal))
    }
    return val
  },
  /**
   * 两数相除
   * @param val1 被除数
   * @param val2 除数
   */
  div (val1, val2, decimal) {
    val1 = Number(val1)
    val2 = Number(val2)
    if (isNaN(val1) || isNaN(val1)) {
      return null
    }
    if (val2 === 0) { // 除数不能为零
      return null
    }
    const val = val1.div(val2)
    if (decimal === undefined) decimal = 8
    if (!isNaN(val) && !isNaN(decimal)) {
      return Number(val.toFixed(decimal))
    }
    return val
  },
  /**
   * 分组后，统计对象某数值字段select count(1) group by filed
   * @param arr
   */
  groupCount (arr = [], groupByField) {
    const groupObject = {}
    arr.map((item) => {
      const groupByFieldValue = item[groupByField]
      if (groupByFieldValue) {
        if (groupByFieldValue in groupObject) {
          groupObject[groupByFieldValue]++
        } else {
          groupObject[groupByFieldValue] = 1
        }
      }
    })

    return groupObject
  },
  /**
   * 分组后，统计对象某数值字段合计值 select sum(fieldAmount) from group by field
   * 参数例子：
   * arr = [{month:1, amount:100},{month:2, amount:200},{month:3, amount:300}];
   * groupField = 'amount';
   * sumField = 'amount';
   * decimal = 2;
   */
  groupSum (arr = [], groupByField, sumField, decimal) {
    const groupObject = {}
    arr.map((item) => {
      const groupByFieldValue = item[groupByField]
      const sumFieldValue = Number(item[sumField])
      if (groupByFieldValue) {
        if (groupByFieldValue in groupObject) {
          const val = Number(groupObject[groupByFieldValue])
          if (!isNaN(val) && !isNaN(sumFieldValue)) {
            groupObject[groupByFieldValue] = val + sumFieldValue
          } else {
            groupObject[groupByFieldValue] = 0
          }
        } else {
          if (!isNaN(sumFieldValue)) {
            groupObject[groupByFieldValue] = sumFieldValue
          } else {
            groupObject[groupByFieldValue] = 0
          }
        }
      }
    })
    if (decimal === undefined) decimal = 8
    if (decimal && !isNaN(decimal)) {
      for (const key in groupObject) {
        groupObject[key] = Number(groupObject[key].toFixed(decimal))
      }
    }
    return groupObject
  },

  /**
   * 不为空（空字符串， 'null', 'undefined', Date, object(Array, Object)）
   * 如果是对象，则可以使用不验证某些对象key参数excludeKeys
   */
  isNotEmpty (val, excludeKeys) {
    return !this.isEmpty(val, excludeKeys)
  },
  /**
   * 为空（空字符串， 'null', 'undefined', Date, object(Array, Object)）
   * 如果是对象，则可以使用不验证某些对象key参数excludeKeys
   */
  isEmpty (val, excludeKeys) {
    if (typeof val === 'number' && val === 0) {
      return false
    }

    if (!val) {
      return true
    }

    if (StringUtil.isString(val)) {
      return StringUtil.trim(val) === '' || val === 'null' || val === 'undefined'
    }

    if (StringUtil.isArray(val) && val.length === 0) {
      return true
    }

    if (StringUtil.isObject(val)) {
      if (val instanceof Date) {
        return false
      } else {
        excludeKeys = excludeKeys || []

        for (const e in val) {
          if (excludeKeys.indexOf(e) === -1 && val[e]) {
            return false
          }
        }

        return true
      }
    }

    return false
  },
  /**
   * 金额验证
   * @param val
   * @returns {boolean}
   */
  isMoney (val) {
    const pattern = /(^[1-9]([0-9]+)?(\.[0-9]{1,3})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9]{1,2})?$)/

    return pattern.test(val)
  },

  /**
   * 是否是Promise对象
   * @param val
   * @returns {*|boolean}
   */
  isPromise (val) {
    return val && typeof val.then === 'function'
  },
  /**
   * is object
   * @param obj
   * @returns {boolean}
   */
  isObject (obj) {
    return obj && Object.prototype.toString.call(obj) === '[object Object]'
  },
  /**
   * 验证对象是否是数组类型
   * @param value
   * @returns {*}
   */
  isArray (value) {
    return typeof Array.isArray === 'function' ? Array.isArray(value) : Object.prototype.toString.call(value) === '[object Array]'
  },
  /**
   * 是否为整数
   * @param val
   * @returns {boolean}
   */
  isInteger (val) {
    const ex = /^\d+$/

    return ex.test(val)
  },
  /**
   * 是否正数
   * @param val
   * @returns {boolean}
   */
  isPositiveNumber (val) {
    return this.isInteger(val) && val > 0
  },
  /**
   * 验证手机号的合法性
   * @param num
   * @returns {boolean}
   */
  isMobileNum (num) {
    if (StringUtil.isEmpty(num)) return false

    const reg = /^1[3|4|5|7|8][0-9]{9}$/

    return reg.test(num)
  },
  /**
   * 固定电话
   * @param val
   * @returns {boolean}
   */
  isTelePhoneNum (val) {
    const reg = /^0\d{2,3}-?\d{7,8}$/

    return reg.test(val)
  },
  /**
   * 固定电话或移动电话
   * @param val
   * @returns {boolean}
   */
  isPhoneNum (val) {
    return this.isTelePhoneNum(val) || this.isMobileNum(val)
  },
  /**
   * @param {string} email
   * @returns {Boolean}
   */
  isEmail (email) {
    // eslint-disable-next-line
    const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
    return reg.test(email)
  },
  /**
   * 验证身份证号格式--简易认证
   */
  isIDNo (val) {
    const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x|Y|y)$)/

    return reg.test(val)
  },
  /**
   * 非负数验证
   * @param val
   * @returns {boolean}
   */
  isDigit (val) {
    const pattern = /^\d+(\.\d+)?$/

    return pattern.test(val)
  },
  /**
   * 判断是否是数字
   */
  isNumber (val) {
    const pattern = /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g

    return pattern.test(val)
  },
  /**
   * 判断是否是数值
   */
  isDecimal (val) {
    const pattern = /(^(-?)[1-9]([0-9]+)?(\.[0-9]{1,28})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/

    return pattern.test(val)
  },
  /**
   * @param {string} str
   * @returns {Boolean}
   */
  isString (str) {
    return typeof str === 'string' || str instanceof String
  },
  /** 是否英文字母
   * @param {string} str
   * @returns {Boolean}
   */
  isAlphabets (str) {
    const reg = /^[A-Za-z]+$/
    return reg.test(str)
  },
  /**
   * @param {string} str
   * @returns {Boolean}
   */
  isLowerCase (str) {
    const reg = /^[a-z]+$/

    return reg.test(str)
  },
  /**
   * @param {string} str
   * @returns {Boolean}
   */
  isUpperCase (str) {
    const reg = /^[A-Z]+$/

    return reg.test(str)
  },
  /**
   * 判断是否是图片
   */
  isImage (fileName) {
    return /.(gif|jpg|jpeg|png|gif|jpg|png)$/i.test(fileName)
  },
  /**
   * @param {string} path
   * @returns {Boolean}
   */
  isExternal (path) {
    return /^(https?:|http:|mailto:|tel:)/.test(path)
  },
  /**
   * @param {string} url
   * @returns {Boolean}
   */
  isURL (url) {
    // eslint-disable-next-line
    const reg1 = /^(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/
    // 中文验证
    const reg2 = /[\u4E00-\u9FA5]/
    // 空格
    const reg3 = /\s/

    // const reg = /^(https?|http|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
    // eslint-disable-next-line
    const reg = /^(https?|http|ftp):\/\/([\w\-_]+(\.[\w\-_]+)+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/

    return (reg1.test(url) && !reg2.test(url) && !reg3.test(url))
  },
  /**
   * 校验密码强度
   * @param {string} pwd
   * @returns {Boolean}
   */
  isValidPassword (pwd) {
    // 低 密码只能包含包含字母、数字，长度是8到30位
    // const reg = new RegExp('(?=.*[0-9])(?=.*[a-zA-Z]).{8,30}');

    // 中 密码必须包含字母、数字、特殊字符，长度是8到30位
    // const reg = new RegExp('(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).{8,30}');

    // 高 密码必须包含大小写字母、数字和特殊字符，长度是8到18位
    const reg = new RegExp('(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[^a-zA-Z0-9]).{8,30}')

    return reg.test(pwd)
  },
  /**
   * 判断是否是微信环境
   * @returns {boolean}
   */
  isWechat () {
    const ua = window.navigator.userAgent.toLowerCase()

    return ua.match(/MicroMessenger/i) === 'micromessenger'
  },
  /**
   * 判断是否是支付宝环境
   * @returns {boolean}
   */
  isAliPay () {
    const ua = window.navigator.userAgent.toLowerCase()

    return ua.indexOf('alipayclient') > -1
  },

  async isBlob (data) {
    try {
      const text = await data.text()
      JSON.parse(text)

      return false
    } catch (error) {
      return true
    }
  },
  /**
   * 是否安卓终端
   */
  isAndroid () {
    const u = navigator.userAgent

    return u.indexOf('Android') > -1 || u.indexOf('Linux') > -1
  },
  /**
   * 是否IOS终端
   */
  isIOS () {
    const u = navigator.userAgent

    return !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
  },
  /**
   * 包含pattern的target字符串
   * @param target 目标字符串
   * @param pattern 包含的字符串
   * @returns {boolean}
   */
  like (target, pattern) {
    if (!target && !pattern) { return false }

    const result = target.indexOf(pattern)

    return result > -1
  },
  /**
   * 以pattern开头的target字符串
   * @param target 目标字符串
   * @param pattern 包含的字符串
   * @returns {boolean}
   */
  likeLeft (target, pattern) {
    if (!target && !pattern) { return false }

    const result = target.indexOf(pattern)

    return result === 0
  },
  /**
   * 以pattern结尾的target字符串
   * @param target 目标字符串
   * @param pattern 包含的字符串
   * @returns {boolean}
   */
  likeRight (target, pattern) {
    if (!target && !pattern) { return false }

    target = target.split('').reverse().join('')
    pattern = pattern.split('').reverse().join('')

    const result = target.indexOf(pattern)
    return result === 0
  },
  /**
   * 将汉字转成全拼拼音，其中每个字的首字母大写
   * @param val 字符串
   */
  getFullChars (val) {
    return val ? pinyin.getFullChars(val) : null
  },
  /**
   * 将汉字转成收拼拼音，其中每个首字母均大写
   * @param val 字符串
   */
  getCamelChars (val) {
    return val ? pinyin.getCamelChars(val) : null
  }

}
